package com.northpool.operator.http.jianmu;

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONObject;
import com.northpool.operator.annotation.InputParam;
import com.northpool.operator.annotation.InputParams;
import com.northpool.operator.annotation.OperatorInfo;
import com.northpool.operator.common.minio.MinIOUtil;
import com.northpool.operator.param.ParamTool;
import com.northpool.operator.type.TypeEnum;
import com.northpool.operator.utils.StpOperatorHelper;
import com.northpool.operator.yaml.NodeDsl;
import io.minio.Result;
import io.minio.messages.Item;
import org.yaml.snakeyaml.Yaml;

import java.io.InputStream;


@OperatorInfo(
        ref = "NodeRegisterOperator",
        name = "节点自动注册",
        description = "扫描对象存储中版本库的节点描述文件，自动注册"
)
public class NodeRegisterOperator extends StpOperatorHelper {

    @InputParams({
            @InputParam(ref = "url", name = "服务地址", desc = "http://northpool.work:8021/stp-jianmu-api", required = true),
            @InputParam(ref = "token", name = "用户Token", desc = "用户登陆后返回的token"),
            @InputParam(ref = "path", name = "minio中对象路径", desc = "minio中对象路径, 如: nodes/piesat/"),
            @InputParam(ref = "minioEndpoint", name = "对象存储地址", desc = "http://ip:port"),
            @InputParam(ref = "bucket", name = "桶名称", desc = "桶名称, 如: stp-minio"),
            @InputParam(ref = "accessKey", name = "minio令牌", desc = "minio令牌", type = TypeEnum.STRING),
            @InputParam(ref = "secretKey", name = "minio密钥", desc = "minio密钥", type = TypeEnum.STRING)
    })
    public NodeRegisterOperator() {
    }

    public String url;
    public String token;
    public String path;

    public static void main(String[] args) throws Exception {
        String bucket = "stp-minio";
        String path = "nodes/piesat/";
        String minioEndpoint = "http://192.168.185.9:9000";
        String accessKey = "northpool";
        String secretKey = "piesat@123";

        MinIOUtil minioUtil = new MinIOUtil(minioEndpoint, accessKey, secretKey);
        NodeRegisterOperator operator = new NodeRegisterOperator();
        operator.url = "http://192.168.185.2/stp-jianmu-api" + "/library/nodes";
        operator.token = "eyJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJ7XCJpZFwiOlwiMVwiLFwiYXZhdGFyVXJsXCI6bnVsbCxcIm5pY2tuYW1lXCI6bnVsbCxcInVzZXJuYW1lXCI6XCJhZG1pblwiLFwiZ2l0UmVwb0lkXCI6bnVsbCxcImdpdFJlcG9cIjpudWxsLFwiZ2l0UmVwb093bmVyXCI6bnVsbCxcImdpdFJlcG9Sb2xlXCI6bnVsbH0iLCJpYXQiOjE3MzYyMzI4MjMsImV4cCI6MTczNjMxOTIyM30.7Z3jR94Ro9UCR7mxzuCVZEryeEBQfFAlE_E5Rc8C5lv7NFbStfvDEtD0fwHY7r_ZRQm-Oc3pYc2eDN9x3wZibg";

        operator.processDirItem(minioUtil, bucket, path);
    }

    @Override
    public void execute(ParamTool paramTool) throws Exception {
        String bucket = paramTool.getStr("bucket");
        String path = paramTool.getStr("path");
        String minioEndpoint = paramTool.getStr("minioEndpoint");
        String accessKey = paramTool.getStr("accessKey");
        String secretKey = paramTool.getStr("secretKey");
        this.url = paramTool.getStr("url") + "/library/nodes";
        this.token = paramTool.getStr("token");

        MinIOUtil minioUtil = new MinIOUtil(minioEndpoint, accessKey, secretKey);
        try {
            processDirItem(minioUtil, bucket, path);
        } catch (Exception ex) {
            error("处理失败" + ex.getMessage());
            failedExit();
        }
    }

    private void processDirItem(MinIOUtil minioUtil, String bucket, String path) throws Exception {
        Iterable<Result<Item>> results = minioUtil.listObjects(bucket, path);
        for (Result<Item> result : results) {
            Item item = result.get();
            boolean dir = item.isDir();
            if (dir) {
                processDirItem(minioUtil, bucket, item.objectName());
            } else {
                String objectName = item.objectName();
                // 跳过隐藏文件
                int index = objectName.lastIndexOf("/");
                String fileName = objectName.substring(index + 1);
                if (fileName.startsWith(".")) {
                    continue;
                }
                String dslPath = path + "node_def.yml";
                boolean exists = minioUtil.objectExists(bucket, dslPath);
                // 有元数据信息的时候才处理
                if (exists) {
                    try {
                        processFileItem(minioUtil, bucket, path, dslPath);
                        break;
                    } catch (Exception ex) {
                        error("节点注册失败：" + objectName);
                    }
                }
            }
        }
    }

    private void processFileItem(MinIOUtil minioUtil, String bucket, String parentPath, String objectName) throws Exception {
        Yaml yaml = new Yaml();
        InputStream inputStream = minioUtil.getObject(bucket, objectName);
        String ymlStr = IoUtil.readUtf8(inputStream);
        NodeDsl nodeDsl = yaml.loadAs(ymlStr, NodeDsl.class);
        String nodeName = StrUtil.isNotBlank(nodeDsl.getName()) ? nodeDsl.getName() : getRef(nodeDsl.getRef());
        JSONObject bodyObj = new JSONObject();
        bodyObj.put("name", nodeName);
        bodyObj.put("description", nodeDsl.getDescription());
        bodyObj.put("dsl", ymlStr);
        HttpResponse execute = HttpUtil.createPost(url)
                .contentType("application/json")
                .header("Authorization", "Bearer " + token)
                .body(bodyObj.toJSONString())
                .execute();

        if (execute.getStatus() != 200) {
            String msg = StrUtil.format("节点: {},请求失败, 响应码: {}, 响应结果: {}", nodeName, execute.getStatus(), execute.body());
            error("注册\"" + nodeName + "\"失败: " + msg);
        }

        log("处理完成：" + objectName);
    }


    private String getOwnerRef(String type) {
        String ref = type.split(":")[0];
        String[] strings = ref.split("/");
        if (strings.length == 1) {
            return "_";
        }
        return strings[0];
    }

    private String getRef(String type) {
        String ref = type.split(":")[0];
        String[] strings = ref.split("/");
        if (strings.length == 1) {
            return ref;
        }
        return strings[1];
    }
}
